#include <unordered_map>
#include <mutex>
#include <memory>
#include "KICachePolicy.hpp"

#ifndef LRUNODE
#define LRUNODE
template <typename Key, typename Value>
struct LruNode
{
private:
    Key m_key;
    Value m_value;
    int m_accessCount;
public:
    std::weak_ptr<LruNode<Key, Value>> m_prev;
    std::shared_ptr<LruNode<Key, Value>> m_next;
public:
    LruNode(Key key, Value value) : m_key(key), m_value(value), m_accessCount(1)
    {}

    Key getKey() const { return m_key; } ;
    Value getVaule() const { return m_value; } ;
    void setValue(const Value& value) { m_value = value; };
    int getAccessCount() const { return m_accessCount; } ;
    void incrementAccessCount() { ++m_accessCount; };
};
#endif

#ifndef LRUCACHE
#define LRUCACHE
template<typename Key, typename Value>
class LRUCache : public KICachePolicy<Key, Value>
{
public:
    LRUCache(int capacity) : m_capacity(capacity)
    {
        // 初始化双向链表
        initLinkList();
    }

    ~LRUCache() 
    {}

    int count()
    {
        return m_map.size();
    }

    // 插入数据
    void put(const Key& key, const Value& value)
    {
        if (m_capacity <= 0)
        {
            return;
        }
        // 如果该节点存在，则更新
        std::lock_guard<std::mutex> lck(m_mtx);
        auto it = m_map.find(key);
        if (it != m_map.end())
        {
            it->second->setValue(value);
            moveMostRecent(it->second);
            return;
        }
        addNewNode(key, value);
    }

    // 获取节点
    bool get(const Key& key, Value& value)
    {
        std::lock_guard<std::mutex> lck(m_mtx);
        auto it = m_map.find(key);
        if (it != m_map.end())
        {
            moveMostRecent(it->second);
            value = it->second->getVaule();
            return true;
        }
        return false;
    }

    Value get(const Key& key)
    {
        Value value{};
        get(key, value);
        return value;
    }

    void remove(const Key& key)
    {
        std::lock_guard<std::mutex> lck(m_mtx);
        auto it = m_map.find(key);
        if (it != m_map.end())
        {
            removeNode(it->second);
            m_map.erase(it);
        }
    }
private:
    // 初始化
    void initLinkList()
    {
        m_head = std::make_shared<LruNode<Key, Value>>(Key(), Value());
        m_tail = std::make_shared<LruNode<Key, Value>>(Key(), Value());
        m_head->m_next = m_tail;
        m_tail->m_prev = m_head;
    }

    void removeLongestUnuse()
    {
        std::shared_ptr<LruNode<Key, Value>> node = m_head->m_next;
        removeNode(node);
        m_map.erase(node->getKey());
    }

    void moveMostRecent(std::shared_ptr<LruNode<Key, Value>> node)
    {
        removeNode(node);
        insert(node);
    }

    void removeNode(std::shared_ptr<LruNode<Key, Value>> node)
    {
        std::shared_ptr<LruNode<Key, Value>> prev = node->m_prev.lock();
        std::shared_ptr<LruNode<Key, Value>> next = node->m_next;
        prev->m_next = next;
        next->m_prev = prev;
        node->m_next = nullptr;
    }

    void addNewNode(const Key& key, const Value& value)
    {
        // 如果已经满了，则删除最久未使用的节点
        if (m_map.size() >= m_capacity)
        {
            removeLongestUnuse();
        }
        std::shared_ptr<LruNode<Key, Value>> newnode = std::make_shared<LruNode<Key, Value>>(key, value);
        insert(newnode);
        m_map.insert({key, newnode});
    }

    void insert(std::shared_ptr<LruNode<Key, Value>> node)
    {
        node->m_next = m_tail;
        node->m_prev = m_tail->m_prev;
        m_tail->m_prev.lock()->m_next = node;
        m_tail->m_prev = node;
    }
private:
    std::shared_ptr<LruNode<Key, Value>> m_head;
    std::shared_ptr<LruNode<Key, Value>> m_tail;
    std::mutex m_mtx;
    std::unordered_map<Key, std::shared_ptr<LruNode<Key, Value>>> m_map;
    int m_capacity;
};
#endif